package pe.gob.foncodes.ssa.bs.common.util;

import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.OrientationRequested;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRReport;
import net.sf.jasperreports.engine.JRResultSetDataSource;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanArrayDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.data.JRCsvDataSource;
import net.sf.jasperreports.engine.data.JRXmlDataSource;
import net.sf.jasperreports.engine.export.JRPrintServiceExporterParameter;
import org.w3c.dom.Document;

public final class JasperReportUtil {

    /** @see web.xml:context-parameter:gob.satt.REPORT_PREFIX */
    private String SUFFIX = ".jasper";
    private String realPath;
    private String datePattern;
    private String numberPattern;
    private char fieldDelimiter;
    private NumberFormat numberFormat;
    private String fileName;
    private boolean attachment;
    private SerializedList<JasperPrint> list;

    public JasperReportUtil() {
        this("Reporte", false);
        ServletContext ctx = ((ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext());
        realPath = "c:/reportes/";
        datePattern = "dd/MM/yyyy";
        numberPattern = "#,#00.00";
        fieldDelimiter = ',';
        numberFormat = NumberFormat.getCurrencyInstance();
    }

    public JasperReportUtil(String filename, boolean attachment) {
        list = new SerializedList<JasperPrint>();
        this.attachment = attachment;
        this.fileName = filename;
    }

    public String getRealPath() {
        return realPath.replace("/", "//");
    }

    public String getDatePattern() {
        return datePattern;
    }

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }

    public String getNumberPattern() {
        return numberPattern;
    }

    public void setNumberPattern(String numberPattern) {
        this.numberPattern = numberPattern;
    }

    public char getFieldDelimiter() {
        return fieldDelimiter;
    }

    public void setFieldDelimiter(char fieldDelimiter) {
        this.fieldDelimiter = fieldDelimiter;
    }

    public NumberFormat getNumberFormat() {
        return numberFormat;
    }

    public void setNumberFormat(NumberFormat numberFormat) {
        this.numberFormat = numberFormat;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setAttachment(boolean b) {
        this.attachment = b;
    }

    public boolean isAttachment() {
        return this.attachment;
    }

    public void exportReport(String name, String format, ResultSet data) {
        exportReport(name, format, data, new HashMap());
    }

    public void exportReport(String name, String format, ResultSet data, Map datasourceParameters) {
        exportReport(name, format, data, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, ResultSet data, Map datasourceParameters, Map exporterParameters) {
        try {
            data.beforeFirst();
        } catch (Exception e) {
            throw new FacesException(e);
        }
        JRResultSetDataSource ds = new JRResultSetDataSource(data);
        exportReport(name, format, ds, datasourceParameters, exporterParameters);
    }

    public void addBatch(String name, ResultSet data) {
        addBatch(name, data, new HashMap());
    }

    public void addBatch(String name, ResultSet data, Map dataSourceParameters) {
        try {
            data.beforeFirst();
        } catch (Exception e) {
            throw new FacesException(e);
        }
        JRResultSetDataSource ds = new JRResultSetDataSource(data);
        addBatch(name, ds, dataSourceParameters);
    }

    public void exportReport(String name, String format, Collection data) {
        exportReport(name, format, data, new HashMap());
    }

    public void exportReport(String name, String format, Collection data, Map datasourceParameters) {
        exportReport(name, format, data, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, Collection data, Map datasourceParameters, Map exporterParameters) {
        exportReport(name, format, new JRBeanCollectionDataSource(data), datasourceParameters, exporterParameters);
    }

    public void addBatch(String name, Collection data) {
        addBatch(name, data, new HashMap());
    }

    public void addBatch(String name, Collection data, Map dataSourceParameters) {
        addBatch(name, new JRBeanCollectionDataSource(data), dataSourceParameters);
    }

    public void exportReport(String name, String format, File csvFile) throws FileNotFoundException {
        exportReport(name, format, csvFile, new HashMap());
    }

    public void exportReport(String name, String format, File csvFile, Map datasourceParameters) throws FileNotFoundException {
        exportReport(name, format, csvFile, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, File csvFile, Map datasourceParameters, Map exporterParameters) throws FileNotFoundException {
        JRCsvDataSource ds = new JRCsvDataSource(csvFile);
        ds.setDateFormat(new SimpleDateFormat(datePattern));
        ds.setFieldDelimiter(fieldDelimiter);
        ds.setNumberFormat(numberFormat);
        exportReport(name, format, ds, datasourceParameters, exporterParameters);
    }

    public void addBatch(String name, File csvFile) throws FileNotFoundException {
        addBatch(name, csvFile, new HashMap());
    }

    public void addBatch(String name, File csvFile, Map dataSourceParameters) throws FileNotFoundException {
        JRCsvDataSource ds = new JRCsvDataSource(csvFile);
        ds.setDateFormat(new SimpleDateFormat(datePattern));
        ds.setFieldDelimiter(fieldDelimiter);
        ds.setNumberFormat(numberFormat);
        addBatch(name, ds, dataSourceParameters);
    }

    public void exportReport(String name, String format, InputStream xmlStream) throws JRException {
        exportReport(name, format, xmlStream, new HashMap());
    }

    public void exportReport(String name, String format, InputStream xmlStream, Map datasourceParameters) throws JRException {
        exportReport(name, format, xmlStream, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, InputStream xmlStream, Map datasourceParameters, Map exporterParameters) throws JRException {
        JRXmlDataSource ds = new JRXmlDataSource(xmlStream);
        ds.setDatePattern(datePattern);
        ds.setNumberPattern(numberPattern);
        ds.setLocale(FacesContext.getCurrentInstance().getExternalContext().getRequestLocale());
        exportReport(name, format, ds, datasourceParameters, exporterParameters);
    }

    public void addBatch(String name, InputStream xmlStream) throws JRException {
        addBatch(name, xmlStream, new HashMap());
    }

    public void addBatch(String name, InputStream xmlStream, Map dataSourceParameters) throws JRException {
        JRXmlDataSource ds = new JRXmlDataSource(xmlStream);
        ds.setDatePattern(datePattern);
        ds.setNumberPattern(numberPattern);
        ds.setLocale(FacesContext.getCurrentInstance().getExternalContext().getRequestLocale());
        addBatch(name, ds, dataSourceParameters);
    }

    public void exportReport(String name, String format, Document document) throws JRException {
        exportReport(name, format, document, new HashMap());
    }

    public void exportReport(String name, String format, Document document, Map datasourceParameters) throws JRException {
        exportReport(name, format, document, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, Document document, Map datasourceParameters, Map exporterParameters) throws JRException {
        exportReport(name, format, new JRXmlDataSource(document), datasourceParameters, exporterParameters);
    }

    public void addBatch(String name, Document document) throws JRException {
        addBatch(name, document, new HashMap());
    }

    public void addBatch(String name, Document document, Map dataSourceParameters) throws JRException {
        addBatch(name, new JRXmlDataSource(document), dataSourceParameters);
    }

    public void exportReport(String name, String format, Object[] data) {
        exportReport(name, format, data, new HashMap());
    }

    public void exportReport(String name, String format, Object[] data, Map datasourceParameters) {
        exportReport(name, format, data, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, Object[] data, Map datasourceParameters, Map exportParameters) {
        exportReport(name, format, new JRBeanArrayDataSource(data), datasourceParameters, exportParameters);
    }

    public void addBatch(String name, Object[] data) {
        addBatch(name, data, new HashMap());
    }

    public void addBatch(String name, Object[] data, Map dataSourceParameters) {
        addBatch(name, new JRBeanArrayDataSource(data), dataSourceParameters);
    }

    public void exportReport(String name, String format, Connection ds) {
        exportReport(name, format, ds, new HashMap());
    }

    public void exportReport(String name, String format) {
        exportReport(name, format, new HashMap());
    }

    public void exportReport(String name, String format, Map datasourceParameters) {
        exportReport(name, format, datasourceParameters, new HashMap());
    }

    public void exportReport(String name, String format, Map datasourceParameters, Map exportParameters) {
        export(format, fillReport(name, new JREmptyDataSource(), datasourceParameters), exportParameters);
    }

    public void exportReport(String name, String format, Connection ds, Map datasourceParameters) {
        exportReport(name, format, ds, datasourceParameters, new HashMap());
    }

    public void exportBatch(String format) {
        exportBatch(format, new HashMap());
    }

    public void exportBatch(String format, Map exporterParameters) {
        if (list.size() == 0) {
            throw new FacesException("Conjunto de reportes para exportacin no definido");
        }
        export(format, list, exporterParameters);
    }

    private JasperPrint fillReport(String name, JRDataSource ds, Map dataSourceParameters) {
        InputStream stream = null;
        JasperPrint jasperPrint = null;
        try {
            stream = loadFile(name);
            jasperPrint = JasperFillManager.fillReport(stream, dataSourceParameters, ds);
        } catch (Exception e) {
            e.printStackTrace();
            error("ERROR 0003: Ocurrio un error al crear el reporte, porfavor comunquese con el rea de TI para solucionar el problema. Disculpe las molestias. ");
            throw new FacesException(e);
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
            }
        }
        return jasperPrint;
    }

    private JasperPrint fillReport(String name, Connection ds, Map dataSourceParameters) {
        InputStream stream = null;
        JasperPrint jasperPrint = null;
        try {
            stream = loadFile(name);
            jasperPrint = JasperFillManager.fillReport(stream, dataSourceParameters, ds);
        } catch (Exception e) {
            e.printStackTrace();
            error("ERROR 0003: Ocurrio un error al crear el reporte, porfavor comunquese con el rea de TI para solucionar el problema. Disculpe las molestias. ");
            throw new FacesException(e);
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
            }
        }
        return jasperPrint;
    }

    public void exportReport(String name, String format, Connection ds, Map dataSourceParameters, Map exporterParameters) {
        export(format, fillReport(name, ds, dataSourceParameters), exporterParameters);
    }

    public void addBatch(String name, Connection ds) {
        addBatch(name, ds, new HashMap());
    }

    public void addBatch(String name, Connection ds, Map dataSourceParameters) {
        list.add(fillReport(name, ds, dataSourceParameters));
    }

    private synchronized void export(String format, JasperPrint jasperPrint, Map exporterParameters) {
        list.dispose();
        list.add(jasperPrint);
        export(format, list, exporterParameters);
    }

    private synchronized void export(String format, SerializedList<JasperPrint> jasperPrintList, Map exporterParameters) {
        JRExporter exporter = null;
        HttpServletResponse response = getResponse();
        FacesContext fcontext = FacesContext.getCurrentInstance();
        JRExporterStrategyFactory factory = null;
        JRExporterStrategy strategy = null;
        try {
            factory = JRExporterStrategyFactory.getInstance();
            strategy = factory.get(format);
            exporter = strategy.export(jasperPrintList, response);
            response.setContentType(strategy.getMimeType());
            String msn = "filename=\"" + (fileName.trim().equals("") ? "\"Reporte" : fileName) + "." +
                    strategy.getFileExtension() + "\"";
            if (attachment) {
                msn = "attachment;" + msn;
            }
            response.setHeader("Content-Disposition", msn);
            response.addHeader("Content-Disposition", msn);
        } catch (Exception e) {
            e.printStackTrace();
            error("ERROR 0005: Ocurrio un error al crear el reporte, porfavor comunquese con el rea de TI para solucionar el problema. Disculpe las molestias. ");
            throw new FacesException(e);
        }
        try {
            exporter.getParameters().putAll(exporterParameters);
            exporter.exportReport();
        } catch (Exception e) {
            e.printStackTrace();
            error("ERROR 0006: Ocurrio un error al crear el reporte, porfavor comunquese con el rea de TI para solucionar el problema. Disculpe las molestias. ");
            throw new FacesException(e);
        }
        if (strategy instanceof PrintServiceExporter) {
            return;
        }
        jasperPrintList.dispose();
        fcontext.responseComplete();
    }

    public void exportReport(String name, String format, JRDataSource ds, Map dataSourceParameters, Map exporterParameters) {
        export(format, fillReport(name, ds, dataSourceParameters), exporterParameters);
    }

    public void addBatch(String name, JRDataSource ds, Map dataSourceParameters) {
        list.add(fillReport(name, ds, dataSourceParameters));
    }

    public void addBatch(String name) {
        addBatch(name, new HashMap());
    }

    public void addBatch(String name, Map dataSourceParameters) {
        list.add(fillReport(name, new JREmptyDataSource(), dataSourceParameters));
    }

    private synchronized InputStream loadFile(String name) {
        InputStream stream = null;
        String path = getRealPath() + name + SUFFIX;
        try {
            stream = new FileInputStream(path);
        } catch (FileNotFoundException ex) {
            throw new IllegalArgumentException("ERROR 0001: Error al acceder al reporte '" + path + "' requerido. ");
        }
        if (stream == null) {
            throw new IllegalArgumentException("ERROR 0002: No se encuentra el reporte con nombre '" + name + "' requerido");
        }
        return stream;
    }

    private synchronized static PrintService getByName(String name) {
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService s : services) {
            if (s.getName().equals(name)) {
                return s;
            }
        }
        return services[0];
    }

    /**
     * Permite obtener los valores de impresin previos a la exportacin <br/>
     * Uso: <br/>
     * JasperReportUtil rep = new JasperReportUtil() ; <br/>
     * //orientation: JRReport.ORIENTATION_LANDSCAPE or JRReport.ORIENTATION_PORTRAIT <br/>
     * //width and heigt in cm <br/>
     * Map printProperties = JasperReportUtil.preparePrinterJob("Xerox DocuPrint P8ex",JRReport.ORIENTATION_LANDSCAPE,1,300,250); <br/>
     * //Example: "testPrint.jasper" <br/>
     * Map dsParameters = new HashMap(); <br/>
     * ... <br/>
     * TypeOfDataSource ds = ... <br/>
     * ... <br/>
     * rep.exportReport("testPrint",JRExporterStrategy.PRINTER,ds,dsParameters,printProperties);
     */
    public static synchronized Map preparePrinterJob(String printerName, byte orientation,
            int copies, float width, float heigt) throws IOException {
        Map p = new HashMap();
        PrinterJob job = PrinterJob.getPrinterJob();
        PrintService selected = getByName(printerName);
        try {
            job.setPrintService(selected);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException("ERROR 0004: No se puede cargar los controladores de impresin");
        }
        p.put(JRPrintServiceExporterParameter.PRINT_SERVICE, selected);
        p.put(JRPrintServiceExporterParameter.PRINT_SERVICE_ATTRIBUTE_SET, selected.getAttributes());

        PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();
       // printRequestAttributeSet.add(JRReport.LANGUAGE_GROOVY.toString());
                //(orientation == JRReport.LANGUAGE_GROOVY) ? OrientationRequested.PORTRAIT : OrientationRequested.LANDSCAPE);
        
        //JRReport.ORIENTATION_PORTRAIT
        
        printRequestAttributeSet.add(new Copies(copies));
        //cm  x  0.39 centimetros a pulgadas
        float w = width * 0.39f;
        float h = heigt * 0.39f;
        printRequestAttributeSet.add(MediaSize.findMedia(w, h, MediaSize.INCH));
        printRequestAttributeSet.add(new MediaPrintableArea(0, 0, w, h, MediaPrintableArea.INCH));
        p.put(JRPrintServiceExporterParameter.PRINT_REQUEST_ATTRIBUTE_SET, printRequestAttributeSet);
        return p;
    }

    /**
     * Agrega un mensaje de error al FacesContext
     */
    public static synchronized void error(String msg) {
        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
        FacesContext fc = FacesContext.getCurrentInstance();
        fc.addMessage(null, facesMsg);
    }

    /**
     * Obtiene el objeto HttpServletResponse
     */
    public static synchronized HttpServletResponse getResponse() {
        FacesContext context = FacesContext.getCurrentInstance();
        return (HttpServletResponse) context.getExternalContext().getResponse();
    }

    /**
     * Establece el valor a una propiedad de HttpSession
     */
    public static synchronized void setSessionProperty(String key, Object value) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.getExternalContext().getSessionMap().put(key, value);
    }
    /**
     * Reporte Comparativo Auditoria 
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
	 public static List getNiveles(String condicion) {

	  List niveles = new ArrayList();
	  StringTokenizer st = new StringTokenizer(condicion, "(,)");
	  while (st.hasMoreTokens()) {
	   try {
	    String nivel = st.nextToken();
	    niveles.add("and nivelid=" + Integer.parseInt(nivel));
	   } catch (NumberFormatException s) {
	    // --ignorar
	   }
	  }
	  return niveles;

	 }
    public static int tipoCombinacionNiveles(String condicion ){
		List<Integer> niveles = new ArrayList<Integer>();
		StringTokenizer st = new StringTokenizer(condicion, "(,)");
		while (st.hasMoreTokens()) {
			try {
				String nivel = st.nextToken();
				niveles.add(Integer.parseInt(nivel));
			} catch (NumberFormatException s) {
				// --ignorar
			}
		}
		int sum =0;
		for(int nivel:niveles){
			sum+=nivel;
		}
		switch(sum){
		case 1:
		case 2:
		case 3:
			if(niveles.size()==1){
				return 1;
			}else{
				return sum;
			}
		default:
			return sum;
		}
	}

	public static String  getCantidadTen3(String serie,int ten3id) {
		return serie.split("=")[1].trim()+"-"+ten3id;
	}

    
}